
void drawAxis (double x, double y, double z, float size = 0.5, short thickness = 1) {

	// force extras into expected ranges
	size = max(size, 0.01);
	thickness = max(thickness, 1);
	thickness = min(thickness, 5);

	glPushAttrib (GL_ENABLE_BIT);
	glDisable (GL_TEXTURE_2D); 

	glPushAttrib(GL_LINE_BIT);
	glLineWidth	(thickness);
	glDisable	(GL_LINE_SMOOTH);
	glDisable	(GL_LINE_STIPPLE);
	
	glBegin (GL_LINES);
		glColor3f(  0.2, 0, 0 );
		glVertex3f( x, y, z );
		glVertex3f( x - size, y, z );

		glColor3f(  0, 0.2, 0 );
		glVertex3f( x, y, z );
		glVertex3f( x, y - size, z );

		glColor3f(  0, 0, 0.2 );
		glVertex3f( x, y, z );
		glVertex3f( x, y, z - size );

		glColor3f(  1, 0, 0 );
		glVertex3f( x, y, z );
		glVertex3f( x + size, y, z );

		glColor3f(  0, 1, 0 );
		glVertex3f( x, y, z );
		glVertex3f( x, y + size, z );

		glColor3f(  0, 0, 1 );
		glVertex3f( x, y, z );
		glVertex3f( x, y, z + size );
	glEnd();
	glPopAttrib();
	glPopAttrib();
}
//

void drawAxis (Vector point, float size = 0.5, short thickness = 1) {
	drawAxis( point.x, point.y, point.z, size, thickness);
}
//

void drawPoint (Vector vert, short size = 1) {
	size = max(size, 1);

	glPushAttrib (GL_ENABLE_BIT | GL_POINT_BIT);

	glDisable	 (GL_TEXTURE_2D); 
	glPointSize	(size);
	glEnable	(GL_POINT_SMOOTH);
	
	glBegin (GL_POINTS);
		glVertex3f( vert.x, vert.y, vert.z );
	glEnd();

	glPopAttrib();
}
//



void drawLine (Vector vert1, Vector vert2, short thickness = 1) {
	thickness = max(thickness, 1);

	glPushAttrib (GL_ENABLE_BIT | GL_LINE_BIT);

	glDisable	(GL_TEXTURE_2D); 
	glLineWidth	(thickness);
	glDisable	(GL_LINE_SMOOTH);
	glDisable	(GL_LINE_STIPPLE);
	
	glBegin (GL_LINES);
		glVertex3f( vert1.x, vert1.y, vert1.z );
		glVertex3f( vert2.x, vert2.y, vert2.z );
	glEnd();

	glPopAttrib();
}
//



void drawTriangleWire (Vector vert1, Vector vert2, Vector vert3, float pushInward = 0) {
	pushInward = min(pushInward, 0.99);
	pushInward = max(pushInward, 0);

	Vertex centroid = (vert1 + vert2 + vert3) / 3;
	vert1 += (centroid - vert1) * pushInward;
	vert2 += (centroid - vert2) * pushInward;
	vert3 += (centroid - vert3) * pushInward;

	drawLine(vert1, vert2);
	drawLine(vert2, vert3);
	drawLine(vert3, vert1);
}
//

void drawTriangleFill (Vector vert1, Vector vert2, Vector vert3, float pushInward = 0) {

	pushInward = min(pushInward, 0.99);
	pushInward = max(pushInward, 0);

	Vertex centroid = (vert1 + vert2 + vert3) / 3;
	vert1 += (centroid - vert1) * pushInward;
	vert2 += (centroid - vert2) * pushInward;
	vert3 += (centroid - vert3) * pushInward;

	glPushAttrib (GL_ENABLE_BIT | GL_POLYGON_BIT);

	glDisable		(GL_TEXTURE_2D); 
	glColorMask		(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	glPolygonMode	(GL_FRONT_AND_BACK, GL_FILL);
	glEnable		(GL_POLYGON_OFFSET_FILL);
			   
	glBegin(GL_TRIANGLES);			
		glVertex3f(vert1.x, vert1.y, vert1.z);
		glVertex3f(vert2.x, vert2.y, vert2.z);
		glVertex3f(vert3.x, vert3.y, vert3.z);
	glEnd();

	glPopAttrib();
}
//

void drawTriangleNormal (Vector vert1, Vector vert2, Vector vert3, float length = 0.1) {
	Vertex centroid = (vert1 + vert2 + vert3) / 3;
	Vector normal = (vert2 - vert1).cross(vert3 - vert1);
	normal.normalize();
	normal *= length;

	drawLine(centroid, normal + centroid);
}
//



void drawText (const char* text, float x, float y, float z) {
	static GLuint textureName = null;
	static PixelPerfectGLFont font;

	// prep the texture on the first run
	if (textureName == null) {
		glGenTextures(1, &textureName);
		font.Create("font.glf", textureName);
	}


	glPushAttrib	(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT);

	glDepthMask		(false);
	glEnable		(GL_TEXTURE_2D);
	glDisable		(GL_DEPTH_TEST);
	glDisable		(GL_CULL_FACE);

	font.Begin		();
	font.TextOut	(text, x, y, z);

	glPopAttrib		();
}
//

// WILL NOT WORK IF THE WINDOW IS RESIZED -- FIX EVENTUALLY!
void drawTextScreen (int x, int y, const char* text, ... ) {
	if (text == null) 
		return;

	char buffer [2048];
	va_list parameters;

	va_start (parameters, text);					
		vsprintf (buffer, text, parameters);
	va_end (parameters);


	glMatrixMode	(GL_PROJECTION);
	glPushMatrix	();
	glLoadIdentity	();
	glOrtho			(0, WINDOW_X_DIM, WINDOW_Y_DIM, 0, -2, 2);

	glMatrixMode	(GL_MODELVIEW);
	glPushMatrix	();
	glLoadIdentity	();
	
	drawText		(buffer, x, y, 0);

	glMatrixMode	(GL_MODELVIEW);
	glPopMatrix		();

	glMatrixMode	(GL_PROJECTION);
	glPopMatrix		();
}
//

void drawTextWorld (Vertex point, double scale, const char* text, ... ) {
	if (text == null) 
		return;

	char buffer [2048];
	va_list parameters;

	va_start (parameters, text);					
		vsprintf (buffer, text, parameters);
	va_end (parameters);


	// put XYZ into camSpace - translating the camera against this 
	// without any rotation gives quick and dirty sprite behaviour
	Transformation camSpace;
	camSpace.loadFromStack( GL_MODELVIEW_MATRIX );
	point = camSpace * point;
	scale *= 0.001;

	glMatrixMode	(GL_MODELVIEW);
	glPushMatrix	();
	glLoadIdentity	();
	glTranslated	(point.x, point.y, point.z);
	glScaled		(scale, -scale, scale);

	drawText		(buffer, 0, 0, 0);

	glPopMatrix		();
}
//

